package java3.io;

import java.util.*;

public class RecursivoLoser {

    private static final int pawn = 1;
    private static final int knight = 2;
    private static final int bishop = 3;
    private static final int rook = 4;
    private static final int queen = 5;
    private static final int king = 6;
    private static final int white = 0;
    private static final int black = 1;
    private static final int vacio = 0;
    private static final int sincolor = 2;
    private UtilLoser util;
    private CalculoLoser calculo;
    public static int request;

    public RecursivoLoser(UtilLoser util, CalculoLoser calculo) {
        this.util = util;
        this.calculo = calculo;
    }

    public Jugadas devolverJugadas(int[][] tablero, int jugador, int rival, int[] jugada) {
        request++;
        Jugadas jugadas = new Jugadas();
        Map<Integer, Movimientos> amenazasescondidas;
        List<int[]> capturas;
        List<Integer> amenazas = new ArrayList<>();
        int pos_king;
        int[] amenazasrival;
        int pos_jaque;

        pos_king = util.devuelvePosicionRey(tablero, jugador);

        pos_jaque = this.devolverCasillasAmenazadas(tablero, amenazas, rival, pos_king);
        amenazasrival = util.convertirListtoArray(amenazas);
        amenazasescondidas = calculo.devolverCasillasAmenazadasEscondidas(tablero,
                rival, jugador, jugada[1], jugada[2], pos_king);

        if (pos_jaque != -1) {//si hay jaque
            calculo.buscarJugadasenJaque(jugadas, tablero, amenazasrival, jugador,
                    jugada[1], jugada[2], amenazasescondidas, pos_king, pos_jaque, rival);
            if (jugadas.isEsObligatorio()) {
                List<int[]> temp = jugadas.getJugadas();
                if (temp.size() > 1) {
                    jugadas.setJugadas(util.ordenarCapturas(temp, amenazasrival));
                }
            } else if (jugadas.isHayJaque()) {
                List<int[]> temp = jugadas.getJugadas();
                if (temp.size() > 1) {
                    jugadas.setJugadas(util.ordenarJaque(temp, tablero, jugador));
                }
            }
        } else {
            capturas = this.devolverCapturas(tablero, jugador, jugada, amenazasrival, amenazasescondidas);
            if (!capturas.isEmpty()) {
                if (capturas.size() > 1) {
                    jugadas.setJugadas(util.ordenarCapturas(capturas, amenazasrival));
                } else {
                    jugadas.setJugadas(capturas);
                }
                jugadas.setEsObligatorio(true);
            }
        }

        return jugadas;
    }

    public List<int[]> devolverCapturas(int[][] tablero, int jugador, int[] j, int[] amenazas, Map<Integer, Movimientos> escondidas) {

        List<int[]> capturas = new ArrayList<>();
        int rival = jugador == white ? black : white;
        Movimientos esc = null;
        int ficha;
        int color;

        for (int i = 0; i < 64; i++) {
            color = tablero[1][i];

            if (color == jugador) {
                if (escondidas != null) {
                    esc = escondidas.get(i);

                    if (esc != null && esc.isSinMovimientos()) {
                        continue;
                    }
                }
                ficha = tablero[0][i];

                switch (ficha) {
                    case pawn:
                        switch (color) {
                            case white:
                                if (i % 8 != 0 && (esc == null || esc.isDiagonalSuperiorIzquierda())) {
                                    if (tablero[0][i + 7] != vacio) {
                                        if (tablero[1][i + 7] == black) {
                                            if (i + 7 > 55 && i + 7 < 64) {
                                                capturas.add(armarJugadaConProm(i, i + 7, pawn, queen));
                                                capturas.add(armarJugadaConProm(i, i + 7, pawn, rook));
                                                capturas.add(armarJugadaConProm(i, i + 7, pawn, bishop));
                                                capturas.add(armarJugadaConProm(i, i + 7, pawn, knight));
                                            } else {
                                                capturas.add(armarJugada(i, i + 7, pawn));
                                            }
                                        }
                                    } else if (j[0] == pawn) {
                                        if (j[1] >= 48 && j[1] <= 55 && j[2] == j[1] - 16 && j[2] == i - 1) {
                                            capturas.add(armarJugada(i, i + 7, pawn));
                                        }
                                    }
                                }
                                if ((i + 1) % 8 != 0 && (esc == null || esc.isDiagonalSuperiorDerecha())) {
                                    if (tablero[0][i + 9] != vacio) {
                                        if (tablero[1][i + 9] == black) {
                                            if (i + 9 > 55 && i + 9 < 64) {
                                                capturas.add(armarJugadaConProm(i, i + 9, pawn, queen));
                                                capturas.add(armarJugadaConProm(i, i + 9, pawn, rook));
                                                capturas.add(armarJugadaConProm(i, i + 9, pawn, bishop));
                                                capturas.add(armarJugadaConProm(i, i + 9, pawn, knight));
                                            } else {
                                                capturas.add(armarJugada(i, i + 9, pawn));
                                            }
                                        }
                                    } else if (j[0] == pawn) {
                                        if (j[1] >= 48 && j[1] <= 55 && j[2] == j[1] - 16 && j[2] == i + 1) {
                                            capturas.add(armarJugada(i, i + 9, pawn));
                                        }
                                    }
                                }
                                break;
                            case black:
                                if ((i + 1) % 8 != 0 && (esc == null || esc.isDiagonalInferiorDerecha())) {
                                    if (tablero[0][i - 7] != vacio) {
                                        if (tablero[1][i - 7] == white) {
                                            if (i - 7 > 0 && i - 7 < 8) {
                                                capturas.add(armarJugadaConProm(i, i - 7, pawn, queen));
                                                capturas.add(armarJugadaConProm(i, i - 7, pawn, rook));
                                                capturas.add(armarJugadaConProm(i, i - 7, pawn, bishop));
                                                capturas.add(armarJugadaConProm(i, i - 7, pawn, knight));
                                            } else {
                                                capturas.add(armarJugada(i, i - 7, pawn));
                                            }
                                        }
                                    } else if (j[0] == pawn) {
                                        if (j[1] >= 8 && j[1] <= 15 && j[2] == j[1] + 16 && j[2] == i + 1) {
                                            capturas.add(armarJugada(i, i - 7, pawn));
                                        }
                                    }
                                }
                                if (i % 8 != 0 && (esc == null || esc.isDiagonalInferiorIzquierda())) {
                                    if (tablero[0][i - 9] != vacio) {
                                        if (tablero[1][i - 9] == white) {
                                            if (i - 9 >= 0 && i - 9 < 8) {
                                                capturas.add(armarJugadaConProm(i, i - 9, pawn, queen));
                                                capturas.add(armarJugadaConProm(i, i - 9, pawn, rook));
                                                capturas.add(armarJugadaConProm(i, i - 9, pawn, bishop));
                                                capturas.add(armarJugadaConProm(i, i - 9, pawn, knight));
                                            } else {
                                                capturas.add(armarJugada(i, i - 9, pawn));
                                            }
                                        }
                                    } else if (j[0] == pawn) {
                                        if (j[1] >= 8 && j[1] <= 15 && j[2] == j[1] + 16 && j[2] == i - 1) {
                                            capturas.add(armarJugada(i, i - 9, pawn));
                                        }
                                    }
                                }
                                break;
                        }
                        break;
                    case knight:
                        //+6 -6
                        if (i < 56 && i % 8 > 1) {
                            if (tablero[1][i + 6] == rival) {
                                capturas.add(armarJugada(i, i + 6, knight));
                            }
                        }
                        if (i > 7 && i % 8 < 6) {
                            if (tablero[1][i - 6] == rival) {
                                capturas.add(armarJugada(i, i - 6, knight));
                            }
                        }
                        //+10 -10
                        if (i < 56 && i % 8 < 6) {
                            if (tablero[1][i + 10] == rival) {
                                capturas.add(armarJugada(i, i + 10, knight));
                            }
                        }
                        if (i > 7 && i % 8 > 1) {
                            if (tablero[1][i - 10] == rival) {
                                capturas.add(armarJugada(i, i - 10, knight));
                            }
                        }
                        //+15 -15
                        if (i < 48 && i % 8 > 0) {
                            if (tablero[1][i + 15] == rival) {
                                capturas.add(armarJugada(i, i + 15, knight));
                            }
                        }
                        if (i > 15 && i % 8 < 7) {
                            if (tablero[1][i - 15] == rival) {
                                capturas.add(armarJugada(i, i - 15, knight));
                            }
                        }
                        //+17 -17
                        if (i < 48 && i % 8 < 7) {
                            if (tablero[1][i + 17] == rival) {
                                capturas.add(armarJugada(i, i + 17, knight));
                            }
                        }
                        if (i > 15 && i % 8 > 0) {
                            if (tablero[1][i - 17] == rival) {
                                capturas.add(armarJugada(i, i - 17, knight));
                            }
                        }
                        break;
                    case bishop:
                        this.buscarCapturasDiagonal(tablero, i, color, true, capturas, bishop, null, esc);
                        break;
                    case rook:
                        this.buscarCapturasHorizontalVertical(tablero, i, color, true, capturas, rook, null, esc);
                        break;
                    case queen:
                        this.buscarCapturasDiagonal(tablero, i, color, true, capturas, queen, null, esc);
                        this.buscarCapturasHorizontalVertical(tablero, i, color, true, capturas, queen, null, esc);
                        break;
                    case king:
                        this.buscarCapturasDiagonal(tablero, i, color, false, capturas, king, amenazas, esc);
                        this.buscarCapturasHorizontalVertical(tablero, i, color, false, capturas, king, amenazas, esc);
                        break;
                }
            }
        }

        return capturas;
    }

    private void buscarCapturasDiagonal(int[][] tablero, int pos, int color, boolean esRecursivo,
            List<int[]> capturas, int pieza, int[] amenazas, Movimientos esc) {

        int factor = 1;
        int val;
        boolean a7 = true,
                b7 = true,
                a9 = true,
                b9 = true;
        do {
            if (a7) {
                val = pos - (7 * factor);
                if (val % 8 > 0 && (esc == null || esc.isDiagonalInferiorDerecha())) {
                    if (tablero[1][val] != sincolor) {
                        if (tablero[1][val] != color) {
                            if (!esRecursivo) {
                                if (!util.siArrayContiene(amenazas, val)) {
                                    capturas.add(armarJugada(pos, val, pieza));
                                }
                            } else {
                                capturas.add(armarJugada(pos, val, pieza));
                            }
                        }
                        a7 = false;
                    }
                } else {
                    a7 = false;
                }
            }
            if (b7) {
                val = pos + (7 * factor);
                if (val < 64 && val % 8 < 7 && (esc == null || esc.isDiagonalSuperiorIzquierda())) {
                    if (tablero[1][val] != sincolor) {
                        if (tablero[1][val] != color) {
                            if (!esRecursivo) {
                                if (!util.siArrayContiene(amenazas, val)) {
                                    capturas.add(armarJugada(pos, val, pieza));
                                }
                            } else {
                                capturas.add(armarJugada(pos, val, pieza));
                            }
                        }
                        b7 = false;
                    }
                } else {
                    b7 = false;
                }
            }
            if (a9) {
                val = pos - (9 * factor);
                if (val >= 0 && val % 8 < 7 && (esc == null || esc.isDiagonalInferiorIzquierda())) {
                    if (tablero[1][val] != sincolor) {
                        if (tablero[1][val] != color) {
                            if (!esRecursivo) {
                                if (!util.siArrayContiene(amenazas, val)) {
                                    capturas.add(armarJugada(pos, val, pieza));
                                }
                            } else {
                                capturas.add(armarJugada(pos, val, pieza));
                            }
                        }
                        a9 = false;
                    }
                } else {
                    a9 = false;
                }
            }
            if (b9) {
                val = pos + (9 * factor);
                if (val < 64 && val % 8 > 0 && (esc == null || esc.isDiagonalSuperiorDerecha())) {
                    if (tablero[1][val] != sincolor) {
                        if (tablero[1][val] != color) {
                            if (!esRecursivo) {
                                if (!util.siArrayContiene(amenazas, val)) {
                                    capturas.add(armarJugada(pos, val, pieza));
                                }
                            } else {
                                capturas.add(armarJugada(pos, val, pieza));
                            }
                        }
                        b9 = false;
                    }
                } else {
                    b9 = false;
                }
            }
            factor++;
        } while ((a7 || b7 || a9 || b9) && factor < 8 && esRecursivo);
    }

    private void buscarCapturasHorizontalVertical(int[][] tablero, int pos, int color,
            boolean esRecursivo, List<int[]> capturas, int pieza, int[] amenazas, Movimientos esc) {
        int factor = 1;
        int val;
        boolean a1 = true,
                b1 = true,
                a8 = true,
                b8 = true;
        do {
            if (a1) {
                val = pos - (1 * factor);
                if (val >= 0 && val % 8 < 7 && (esc == null || esc.isHorizontalIzquierda())) {
                    if (tablero[1][val] != sincolor) {
                        if (tablero[1][val] != color) {
                            if (!esRecursivo) {
                                if (!util.siArrayContiene(amenazas, val)) {
                                    capturas.add(armarJugada(pos, val, pieza));
                                }
                            } else {
                                capturas.add(armarJugada(pos, val, pieza));
                            }
                        }
                        a1 = false;
                    }
                } else {
                    a1 = false;
                }
            }
            if (b1) {
                val = pos + (1 * factor);
                if (val % 8 > 0 && (esc == null || esc.isHorizontalDerecha())) {
                    if (tablero[1][val] != sincolor) {
                        if (tablero[1][val] != color) {
                            if (!esRecursivo) {
                                if (!util.siArrayContiene(amenazas, val)) {
                                    capturas.add(armarJugada(pos, val, pieza));
                                }
                            } else {
                                capturas.add(armarJugada(pos, val, pieza));
                            }
                        }
                        b1 = false;
                    }
                } else {
                    b1 = false;
                }
            }
            if (a8) {
                val = pos - (8 * factor);
                if (val >= 0 && (esc == null || esc.isVerticalInferior())) {
                    if (tablero[1][val] != sincolor) {
                        if (tablero[1][val] != color) {
                            if (!esRecursivo) {
                                if (!util.siArrayContiene(amenazas, val)) {
                                    capturas.add(armarJugada(pos, val, pieza));
                                }
                            } else {
                                capturas.add(armarJugada(pos, val, pieza));
                            }
                        }
                        a8 = false;
                    }
                } else {
                    a8 = false;
                }
            }
            if (b8) {
                val = pos + (8 * factor);
                if (val < 64 && (esc == null || esc.isVerticalSuperior())) {
                    if (tablero[1][val] != sincolor) {
                        if (tablero[1][val] != color) {
                            if (!esRecursivo) {
                                if (!util.siArrayContiene(amenazas, val)) {
                                    capturas.add(armarJugada(pos, val, pieza));
                                }
                            } else {
                                capturas.add(armarJugada(pos, val, pieza));
                            }
                        }
                        b8 = false;
                    }
                } else {
                    b8 = false;
                }
            }
            factor++;
        } while ((a1 || b1 || a8 || b8) && factor < 8 && esRecursivo);
    }

    public int devolverCasillasAmenazadas(int[][] tablero,
            List<Integer> amenazas, int jugador, int pos_king) {

        int pos_jaque = -1;
        int ficha;
        int color;

        for (int i = 0; i < 64; i++) {
            color = tablero[1][i];

            if (color == jugador) {
                ficha = tablero[0][i];
                switch (ficha) {
                    case pawn:
                        switch (color) {
                            case white:
                                if (i % 8 != 0) {
                                    if (i + 7 == pos_king) {
                                        pos_jaque = pos_jaque == -1 ? i : 100;
                                    } else {
                                        amenazas.add(i + 7);
                                    }
                                }
                                if ((i + 1) % 8 != 0) {
                                    if (i + 9 == pos_king) {
                                        pos_jaque = pos_jaque == -1 ? i : 100;
                                    } else {
                                        amenazas.add(i + 9);
                                    }
                                }
                                break;
                            case black:
                                if ((i + 1) % 8 != 0) {
                                    if (i - 7 == pos_king) {
                                        pos_jaque = pos_jaque == -1 ? i : 100;
                                    } else {
                                        amenazas.add(i - 7);
                                    }
                                }
                                if (i % 8 != 0) {
                                    if (i - 9 == pos_king) {
                                        pos_jaque = pos_jaque == -1 ? i : 100;
                                    } else {
                                        amenazas.add(i - 9);
                                    }
                                }
                                break;
                        }
                        break;
                    case knight:
                        //+6 -6
                        if ((i < 56 && i % 8 > 1)) {
                            if (i + 6 == pos_king) {
                                pos_jaque = pos_jaque == -1 ? i : 100;
                            } else {
                                amenazas.add(i + 6);
                            }
                        }
                        if (i > 7 && i % 8 < 6) {
                            if (i - 6 == pos_king) {
                                pos_jaque = pos_jaque == -1 ? i : 100;
                            } else {
                                amenazas.add(i - 6);
                            }
                        }
                        //+10 -10
                        if (i < 56 && i % 8 < 6) {
                            if (i + 10 == pos_king) {
                                pos_jaque = pos_jaque == -1 ? i : 100;
                            } else {
                                amenazas.add(i + 10);
                            }
                        }
                        if (i > 7 && i % 8 > 1) {
                            if (i - 10 == pos_king) {
                                pos_jaque = pos_jaque == -1 ? i : 100;
                            } else {
                                amenazas.add(i - 10);
                            }
                        }
                        //+15 -15
                        if (i < 48 && i % 8 > 0) {
                            if (i + 15 == pos_king) {
                                pos_jaque = pos_jaque == -1 ? i : 100;
                            } else {
                                amenazas.add(i + 15);
                            }
                        }
                        if (i > 15 && i % 8 < 7) {
                            if (i - 15 == pos_king) {
                                pos_jaque = pos_jaque == -1 ? i : 100;
                            } else {
                                amenazas.add(i - 15);
                            }
                        }
                        //+17 -17
                        if (i < 48 && i % 8 < 7) {
                            if (i + 17 == pos_king) {
                                pos_jaque = pos_jaque == -1 ? i : 100;
                            } else {
                                amenazas.add(i + 17);
                            }
                        }
                        if ((i > 15 && i % 8 > 0)) {
                            if (i - 17 == pos_king) {
                                pos_jaque = pos_jaque == -1 ? i : 100;
                            } else {
                                amenazas.add(i - 17);
                            }
                        }
                        break;
                    case bishop:
                        pos_jaque = this.buscarAmenazasDiagonal(tablero, i, true, amenazas, pos_king, pos_jaque);
                        break;
                    case rook:
                        pos_jaque = this.buscarAmenazasHorizontalVertical(tablero, i, true, amenazas, pos_king, pos_jaque);
                        break;
                    case queen:
                        pos_jaque = this.buscarAmenazasDiagonal(tablero, i, true, amenazas, pos_king, pos_jaque);
                        pos_jaque = this.buscarAmenazasHorizontalVertical(tablero, i, true, amenazas, pos_king, pos_jaque);
                        break;
                    case king:
                        this.buscarAmenazasDiagonal(tablero, i, false, amenazas, pos_king, pos_jaque);
                        this.buscarAmenazasHorizontalVertical(tablero, i, false, amenazas, pos_king, pos_jaque);
                        break;
                }
            }
        }

        return pos_jaque;
    }

    private int buscarAmenazasDiagonal(int[][] tablero, int pos, boolean esRecursivo,
            List<Integer> amenazas, int pos_king, int jaque) {

        int pos_jaque = jaque;
        int factor = 1;
        int val;
        boolean a7 = true,
                b7 = true,
                a9 = true,
                b9 = true;
        do {
            if (a7) {
                val = pos - (7 * factor);
                if (val % 8 > 0) {
                    if (tablero[1][val] != sincolor && val != pos_king) {
                        a7 = false;
                    }
                    if (val == pos_king) {
                        pos_jaque = pos_jaque == -1 ? pos : 100;
                    } else {
                        amenazas.add(val);
                    }
                } else {
                    a7 = false;
                }
            }
            if (b7) {
                val = pos + (7 * factor);
                if (val < 64 && val % 8 < 7) {
                    if (tablero[1][val] != sincolor && val != pos_king) {
                        b7 = false;
                    }
                    if (val == pos_king) {
                        pos_jaque = pos_jaque == -1 ? pos : 100;
                    } else {
                        amenazas.add(val);
                    }
                } else {
                    b7 = false;
                }
            }
            if (a9) {
                val = pos - (9 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (tablero[1][val] != sincolor && val != pos_king) {
                        a9 = false;
                    }
                    if (val == pos_king) {
                        pos_jaque = pos_jaque == -1 ? pos : 100;
                    } else {
                        amenazas.add(val);
                    }
                } else {
                    a9 = false;
                }
            }
            if (b9) {
                val = pos + (9 * factor);
                if (val < 64 && val % 8 > 0) {
                    if (tablero[1][val] != sincolor && val != pos_king) {
                        b9 = false;
                    }
                    if (val == pos_king) {
                        pos_jaque = pos_jaque == -1 ? pos : 100;
                    } else {
                        amenazas.add(val);
                    }
                } else {
                    b9 = false;
                }
            }
            factor++;
        } while ((a7 || b7 || a9 || b9) && factor < 8 && esRecursivo);

        return pos_jaque;
    }

    private int buscarAmenazasHorizontalVertical(int[][] tablero, int pos,
            boolean esRecursivo, List<Integer> amenazas, int pos_king, int jaque) {
        int pos_jaque = jaque;
        int factor = 1;
        int val;
        boolean a1 = true,
                b1 = true,
                a8 = true,
                b8 = true;
        do {
            if (a1) {
                val = pos - (1 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (tablero[1][val] != sincolor && val != pos_king) {
                        a1 = false;
                    }
                    if (val == pos_king) {
                        pos_jaque = pos_jaque == -1 ? pos : 100;
                    } else {
                        amenazas.add(val);
                    }
                } else {
                    a1 = false;
                }
            }
            if (b1) {
                val = pos + (1 * factor);
                if (val % 8 > 0) {
                    if (tablero[1][val] != sincolor && val != pos_king) {
                        b1 = false;
                    }

                    if (val == pos_king) {
                        pos_jaque = pos_jaque == -1 ? pos : 100;
                    } else {
                        amenazas.add(val);
                    }
                } else {
                    b1 = false;
                }
            }
            if (a8) {
                val = pos - (8 * factor);
                if (val >= 0) {
                    if (tablero[1][val] != sincolor && val != pos_king) {
                        a8 = false;
                    }
                    if (val == pos_king) {
                        pos_jaque = pos_jaque == -1 ? pos : 100;
                    } else {
                        amenazas.add(val);
                    }
                } else {
                    a8 = false;
                }
            }
            if (b8) {
                val = pos + (8 * factor);
                if (val < 64) {
                    if (tablero[1][val] != sincolor && val != pos_king) {
                        b8 = false;
                    }
                    if (val == pos_king) {
                        pos_jaque = pos_jaque == -1 ? pos : 100;
                    } else {
                        amenazas.add(val);
                    }
                } else {
                    b8 = false;
                }
            }
            factor++;
        } while ((a1 || b1 || a8 || b8) && factor < 8 && esRecursivo);

        return pos_jaque;
    }

    private int[] armarJugada(int ini, int fin, int ficha) {
        return new int[]{ficha, ini, fin};
    }

    private int[] armarJugadaConProm(int ini, int fin, int ficha, int prom) {
        return new int[]{ficha, ini, fin, prom};
    }
}
